package com.wxmp.wxapi.ctrl;


import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.wxmp.core.common.PayConstant;
import com.wxmp.core.util.wx.WxPayProperties;
import com.wxmp.core.util.wx.WxPayUtil;
import com.wxmp.wxapi.domain.WxpayOrder;
import com.wxmp.wxapi.service.UnionCardAccountService;
import com.wxmp.wxapi.service.WxRechargeService;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;


/**
 * @author JohnKee
 */
@RestController
public class Notify4WxPayController {

    private static final Logger logger = LoggerFactory.getLogger(Notify4WxPayController.class);

    @Autowired
    private WxRechargeService wxRechargeService;

    @Autowired
    private UnionCardAccountService unionCardAccountService;

    @Resource
    private WxPayProperties wxPayProperties;

    @RequestMapping("/notify/pay/wxPayNotifyRes.htm")
    @ResponseBody
    public String wxPayNotifyRes(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        return doWxPayRes(request, response);
    }

    private String doWxPayRes(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            WxPayService wxPayService = new WxPayServiceImpl();
            WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlResult);
            Map<String, Object> payContext = new HashMap();
            payContext.put("parameters", result);
            // 验证业务数据是否正确,验证通过后返回PayOrder和WxPayConfig对象
            if (!verifyWxPayParams(payContext)) {
                return WxPayNotifyResponse.fail((String) payContext.get("retMsg"));
            }

            WxpayOrder payOrder = (WxpayOrder) payContext.get("payOrder");
            WxPayConfig wxPayConfig = (WxPayConfig) payContext.get("wxPayConfig");
            wxPayService.setConfig(wxPayConfig);
            // 这里做了签名校验(这里又做了一次xml转换对象,可以考虑优化)
            wxPayService.parseOrderNotifyResult(xmlResult);
            // 处理订单
            byte payStatus = payOrder.getStatus(); // 0：订单生成，1：支付中，-1：支付失败，2：支付成功，3：业务处理完成，-2：订单过期
            if (payStatus != PayConstant.PAY_STATUS_SUCCESS && payStatus != PayConstant.PAY_STATUS_COMPLETE) {
                payOrder.setPaySuccTime(System.currentTimeMillis());
                payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS);
                int updatePayOrderRows = wxRechargeService.updatePayOrderStatus(payOrder);
                if (updatePayOrderRows != 1) {
                    logger.error("更新支付状态失败,将payOrderId={},更新payStatus={}失败", payOrder.getId(), PayConstant.PAY_STATUS_SUCCESS);
                    return WxPayNotifyResponse.fail("处理订单失败");
                }
                logger.error("更新支付状态成功,将payOrderId={},更新payStatus={}成功", payOrder.getId(), PayConstant.PAY_STATUS_SUCCESS);
                payOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS);
            }
            // 业务系统后端通知
            int notifyFlag = unionCardAccountService.doNotify(payOrder);
            if(notifyFlag != 1){
                logger.error("卡处理失败");
                return WxPayNotifyResponse.fail("处理订单失败");
            }
            logger.info("====== 完成接收微信支付回调通知 ======");
            return WxPayNotifyResponse.success("处理成功");
        } catch (WxPayException e) {
            //出现业务错误
            logger.error("微信回调结果异常,异常原因", e);
            logger.info("err_code:", e.getErrCode());
            logger.info("err_code_des:", e.getErrCodeDes());
            return WxPayNotifyResponse.fail(e.getMessage());
        } catch (Exception e) {
            logger.error("微信回调结果异常,异常原因", e);
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }


    private boolean verifyWxPayParams(Map<String, Object> payContext) {
        WxPayOrderNotifyResult params = (WxPayOrderNotifyResult) payContext.get("parameters");

        //校验结果是否成功
        if (!PayConstant.RETURN_VALUE_SUCCESS.equalsIgnoreCase(params.getResultCode())
                && !PayConstant.RETURN_VALUE_SUCCESS.equalsIgnoreCase(params.getReturnCode())) {
            logger.error("returnCode={},resultCode={},errCode={},errCodeDes={}", params.getReturnCode(), params.getResultCode(), params.getErrCode(), params.getErrCodeDes());
            payContext.put("retMsg", "notify data failed");
            return false;
        }

        Integer total_fee = params.getTotalFee();            // 总金额
        String out_trade_no = params.getOutTradeNo();            // 商户系统订单号

        // 查询payOrder记录
        String payOrderId = out_trade_no;
        WxpayOrder payOrder = wxRechargeService.getPayOrderByPrimaryKey(new Long(payOrderId));
        if (payOrder == null) {
            logger.error("Can't found payOrder form db. payOrderId={}, ", payOrderId);
            payContext.put("retMsg", "Can't found payOrder");
            return false;
        }


/*        String MCH_ID = payOrder.getMchId();
        String channelId = payOrder.getChannelId();
        PayChannel payChannel = payChannelService.selectPayChannel(channelId, MCH_ID);
        if(payChannel == null) {
            logger.error("Can't found payChannel form db. MCH_ID={} channelId={}, ", payOrderId, MCH_ID, channelId);
            payContext.put("retMsg", "Can't found payChannel");
            return false;
        }*/
        payContext.put("wxPayConfig", WxPayUtil.getWxPayConfig(wxPayProperties.getChannelParams()));

        // 核对金额
        long wxPayAmt = new BigDecimal(total_fee).longValue();
        long dbPayAmt = payOrder.getAmount().longValue();
        if (dbPayAmt != wxPayAmt) {
            logger.error("db payOrder record payPrice not equals total_fee. total_fee={},payOrderId={}", total_fee, payOrderId);
            payContext.put("retMsg", "total_fee is not the same");
            return false;
        }
        payContext.put("payOrder", payOrder);
        return true;
    }
}
